#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>
#include "task.hpp"
#include <cstdlib>

#define PROCESS_NUM 5 // 5个子进程
#define TASK_NUM 5    // 5个任务

int waitTask(int fd, bool &quit) // 阻塞读取任务
{
    int command;
    quit = read(fd, &command, sizeof(command));
    return command;
}

// 父进程通过管道派发任务
void sendTask(std::vector<std::pair<int, int>> id2fd)
{
    static int child = 0;
    child %= id2fd.size();
    int command = rand() % TASK_NUM;
    write(id2fd[child].second, &command, sizeof(command)); // 给子进程派任务
    ++child;                                               // 循环选择子进程
}

int main()
{

    Task task;                              // 创建task
    std::vector<std::pair<int, int>> id2fd; // 记录子进程id和写端

    for (size_t i = 0; i < PROCESS_NUM; i++)
    {
        // 1.创建匿名管道
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        assert(n != -1);
        std::cout << "---pipe Create Done!!---" << std::endl;

        // 2.创建子进程
        pid_t id = fork();
        assert(id != -1);
        if (id == 0)
        {
            std::cout << "---fork Done!!---" << std::endl;
            // 子进程
            //  3.子进程执行任务
            close(pipefd[1]); // 子进程关闭写端

            while (true)
            {
                bool quit = false;
                int command = waitTask(pipefd[0], quit); // 阻塞读取任务
                if (quit == false)
                {
                    std::cout << "---child quit!!---" << std::endl;
                    break; // 写端关闭 子进程也退出
                }
                // 执行任务
                task.run(getpid(), command);
            }
            exit(1);
        }
        // 父进程关闭读端
        close(pipefd[0]);
        // 记录子进程的id和写端
        id2fd.push_back({id, pipefd[1]});
    }

    srand((unsigned long)time(nullptr));
    // 4.父进程通过管道派发任务
    int cnt = 10;
    while (cnt--)
    {
        sendTask(id2fd);
        sleep(2);
    }
    // 5.关闭写端
    for (auto &iter : id2fd)
    {
        close(iter.second);
    }

    // 6.进程回收
    for (auto &iter : id2fd)
    {
        waitpid(iter.first, nullptr, 0);
    }
}